package com.oromwin.repos.socket.request.media;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;

import org.apache.commons.logging.Log;

import com.oromwin.repos.common.Common;
import com.oromwin.repos.common.Logger;
import com.oromwin.repos.common.ReposException;
import com.oromwin.repos.common.Common.ReposResult;
import com.oromwin.repos.common.Common.Status;
import com.oromwin.repos.common.helper.DBHelper;
import com.oromwin.repos.common.helper.FSHelper;
import com.oromwin.repos.common.helper.IOHelper;
import com.oromwin.repos.data.AbstractReposTable;
import com.oromwin.repos.data.MediaTable;
import com.oromwin.repos.data.VolumeTable;
import com.oromwin.repos.server.LockObject;
import com.oromwin.repos.socket.request.AbstractRequest;
import com.oromwin.repos.socket.request.RequestAction;
import com.oromwin.repos.socket.response.Response;
import com.oromwin.repos.socket.response.media.CreateMediaResponse;

public class CreateMediaRequest extends AbstractRequest implements RequestAction {
    private Log log = Logger.getLog(CreateMediaRequest.class);
    private String VolumeName = null;
    private File MediaPath = null;
    private Long MediaMaxBytes = 0L;
    private String VolumeId = null;
    
    public CreateMediaRequest() {
    }
    
    public CreateMediaRequest(String volumeName, File mediaPath, Long mediaMaxBytes) {
        VolumeName = volumeName;
        MediaPath = mediaPath;
        MediaMaxBytes = mediaMaxBytes;
    }
    
    @Override
    public void receive(DataInputStream dis, LockObject lockObject) throws ReposException {
        try {
            VolumeName = IOHelper.readUTF8(dis);
            MediaPath = new File(IOHelper.readUTF8(dis));
            MediaMaxBytes = dis.readLong();
        } catch (IOException e) {
            throw ReposException.create(log, e);
        }
    }

    @Override
    public Response run() {
        CreateMediaResponse res = null;
        try {
            _volumeTable = (VolumeTable) getParentReposTable();
            VolumeId = _volumeTable.getVolumeId();
            _mediaTable = new MediaTable(_volumeTable.getVolumeId(), id(), MediaPath, MediaMaxBytes, 0L, 0, Status.CREATE, Common.datetime(), Common.datetime());
            checkDependentObjectNotExists();
            checkSameObjectExists();
            checkFreeSpaceExists();
            DBHelper.insertTable(_mediaTable);
            res = new CreateMediaResponse(ReposResult.Success, "Succeeded to create media");
        } catch (ReposException e) {
            res = new CreateMediaResponse(ReposResult.Failure, e.getMessage());
        }
        return res;
    }

    @Override
    public void send(DataOutputStream dos) throws ReposException {
        try {
            IOHelper.writeUTF8(dos, this.getClass().getCanonicalName());
            IOHelper.writeUTF8(dos, VolumeName);
            IOHelper.writeUTF8(dos, MediaPath.toString());
            dos.writeLong(MediaMaxBytes);
            dos.flush();
        } catch (IOException e) {
            throw ReposException.create(log, e);
        }
    }

    @Override
    public void checkFreeSpaceExists() throws ReposException {
        File file = _mediaTable.getMediaPath();
        Long bytes = _mediaTable.getMediaMaxBytes();
        Long freeSpace = 0L;
        try {
            freeSpace = FSHelper.df(file);
        } catch (NullPointerException e) {
            String message = String.format("Can't find requested directory, path {%s}", file);
            throw ReposException.create(log, e, message);
        } catch (SecurityException e) {
            String message = String.format("Can't access to requested directory, path {%s}", file);
            throw ReposException.create(log, e, message);
        }
        if (freeSpace.compareTo(bytes) < 0) {
            String message = String.format("Not enough disk space available, spaceAvailable:requestedBytes {%d:%d}", freeSpace, bytes);
            throw ReposException.create(log, message); 
        }
    }
    
    @Override
    public void checkSameObjectExists() throws ReposException {
        File file = _mediaTable.getMediaPath();
        if (!FSHelper.ls(file)) {
            String message = String.format("'%s' MediaPath does not exists on the server", file);
            throw ReposException.create(log, message); 
        }
    }

    @Override
    public void checkDependentObjectNotExists() throws ReposException {
        String whereClause = String.format("MediaStatus < 2 AND VolumeId = '%s' and MediaPath = '%s'", VolumeId, MediaPath);
        List<AbstractReposTable> list = DBHelper.selectTable(MediaTable.class, whereClause);
        if (list.size() != 0) {
            String message = String.format("'%s' VolumeName already exists in database, VolumeId:MediaName {%s:%s}", VolumeName, VolumeId, MediaPath);
            throw ReposException.create(log, message); 
        }
    }
    
    @Override
    public AbstractReposTable getCurrentReposTable() throws ReposException {
        return null;
    }
    
    @Override
    public AbstractReposTable getParentReposTable() throws ReposException {
        AbstractReposTable reposTable = null;
        String whereClause = String.format("VolumeStatus < 2 AND VolumeName = '%s'", VolumeName);
        List<AbstractReposTable> reposTables = DBHelper.selectTable(VolumeTable.class, whereClause);
        if (reposTables != null && reposTables.size() == 1) {
            reposTable = reposTables.get(0);
        } else {
            String message = String.format("'%s' VolumeName does not exists in database, tableSize:whereClause {%d:%s}", VolumeName, reposTables.size(), whereClause);
            throw ReposException.create(log, message); 
        }
        return reposTable;
    }
}
